package rise.comunity;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;

import rise.ui.Conversation;
import rise.ui.UserListActivity;

public class Community {
	private static Community c = null;
	public static final String broadcastWildcard = "Broadcast";
	private HashMap<String, User> users;
	private HashMap<String, ArrayList<String>> conversations;
	private ArrayList<String> userList;

	private Community() {
		this.users = new HashMap<String, User>();
		this.conversations = new HashMap<String, ArrayList<String>>();
		this.userList = new ArrayList<String>();
		this.addUser(
				new User(Status.ONLINE, Community.broadcastWildcard, 0, 0));
	}

	public boolean contains(User user) {
		synchronized (this) {
			return users.containsKey(user.getUsername());
		}
	}

	public boolean contains(String username) {
		synchronized (this) {
			return users.containsKey(username);
		}
	}

	public int size() {
		synchronized (this) {
			return this.users.size();
		}
	}

	public Status getUserStatus(String username) {
		synchronized (this) {
			User user = users.get(username);
			return user.getStatus();
		}
	}

	public GPSLocation getUserGPSLocation(String username) {
		synchronized (this) {
			User user = users.get(username);
			return user.getGPSLocation();
		}
	}

	public void setUserGPSLocation(String username, double lat, double lon) {
		synchronized (this) {
			User user = users.get(username);
			user.setLat(lat);
			user.setLon(lon);

			users.put(username, user);
		}

	}

	public void setUserStatus(String username, Status status) {
		synchronized (this) {
			User user = users.get(username);
			Status oldStatus = user.getStatus();
			if (status == oldStatus) {
				return;
			}

			user.setStatus(status);
			users.put(username, user);

			int conversationSize = conversations.get(username).size();
			if (conversationSize == 0) {
				this.moveUser(username, oldStatus, status);
			} else {
				this.moveSender(username, oldStatus, status);
			}
			/****/

			UserListActivity.handler.sendEmptyMessage(0);
			Conversation.handler.sendEmptyMessage(0);
		}
	}

	public void addUser(User user) {
		synchronized (this) {
			this.users.put(user.getUsername(), user);

			ArrayList<String> conversation = new ArrayList<String>();
			if (user.getUsername().equalsIgnoreCase(broadcastWildcard)) {
				this.userList.add(0, broadcastWildcard);
				this.conversations.put(broadcastWildcard, conversation);
			} else if (this.conversations.put(user.getUsername(), conversation) == null) {
				this.addUserToUIList(user.getUsername(), user.getStatus());
			}

			/****/
			UserListActivity.handler.sendEmptyMessage(0);
		}
	}

	/***/

	public void addMessageFrom(String username, String text) {
		synchronized (this) {
			ArrayList<String> messages = this.conversations.get(username);
			int originalConversationSize = messages.size();
			messages.add(messages.size(), text);
			this.conversations.put(username, messages);

			if (originalConversationSize == 0) {
				this.moveUserToSenders(username, this.users.get(username)
						.getStatus());
			}
			/****/
			UserListActivity.handler.sendEmptyMessage(0);
			Conversation.handler.sendEmptyMessage(0);
		}
	}

	public ArrayList<String> getMessagesFrom(String username) {
		synchronized (this) {
			ArrayList<String> conversation = this.conversations.get(username);
			if(conversation == null){
				conversation = new ArrayList<String>();
				this.conversations.put(username, conversation);
			}
			return conversation;
		}
	}

	private int getMessagesCardinality(String username) {
		return this.conversations.get(username).size();
	}

	public int getMessagesCardinalityFrom(String username) {
		synchronized (this) {
			return this.getMessagesCardinality(username);
		}
	}

	public void flushConversationFrom(String username) {
		synchronized (this) {
			int originalConversationSize = this
					.getMessagesCardinality(username);
			this.conversations.put(username, new ArrayList<String>());

			if (originalConversationSize != 0)
				this.moveSenderToUsers(username, users.get(username)
						.getStatus());
			/****/
			UserListActivity.handler.sendEmptyMessage(0);
			Conversation.handler.sendEmptyMessage(0);
		}
	}

	private int iBusySender = 1, iOfflineSender = 1, iOnlineUser = 1,
			iBusyUser = 1, iOfflineUser = 1;

	// ONS//BS//OFFS//ONU//BU//OFFU

	private void addSenderToUIList(String username, Status status) {
		if (Status.ONLINE == status) {
			this.addOnlineSender(username);
		} else if (Status.BUSY == status) {
			this.addBusySender(username);
		} else {
			this.addOfflineSender(username);
		}
	}

	private void addOnlineSender(String username) {
		iBusySender++;
		iOfflineSender++;
		iOnlineUser++;
		iBusyUser++;
		iOfflineUser++;
		this.userList.add(1, username);
	}

	private void addBusySender(String username) {
		iOfflineSender++;
		iOnlineUser++;
		iBusyUser++;
		iOfflineUser++;
		this.userList.add(iBusySender, username);
	}

	private void addOfflineSender(String username) {
		iOnlineUser++;
		iBusyUser++;
		iOfflineUser++;
		this.userList.add(iOfflineSender, username);
	}

	private void moveSender(String username, Status oldStatus, Status newStatus) {
		this.userList.remove(username);
		if (Status.ONLINE == oldStatus) {
			iBusySender--;
			iOfflineSender--;
			iOnlineUser--;
			iBusyUser--;
			iOfflineUser--;
			if (Status.BUSY == newStatus) {
				this.addBusySender(username);
			} else if (Status.OFFLINE == newStatus) {
				this.addOfflineSender(username);
			} else {
				this.addOnlineSender(username);
			}
		} else if (Status.BUSY == oldStatus) {
			iOfflineSender--;
			iOnlineUser--;
			iBusyUser--;
			iOfflineUser--;
			if (Status.ONLINE == newStatus) {
				this.addOnlineSender(username);
			} else if (Status.OFFLINE == newStatus) {
				this.addOfflineSender(username);
			} else {
				this.addBusySender(username);
			}
		} else {
			iOnlineUser--;
			iBusyUser--;
			iOfflineUser--;
			if (Status.ONLINE == newStatus) {
				this.addOnlineSender(username);
			} else if (Status.BUSY == newStatus) {
				this.addBusySender(username);
			} else {
				this.addOfflineSender(username);
			}
		}
	}

	private void moveUser(String username, Status oldStatus, Status newStatus) {
		this.userList.remove(username);
		if (Status.ONLINE == oldStatus) {
			iBusyUser--;
			iOfflineUser--;
			if (Status.BUSY == newStatus) {
				this.addBusyUser(username);
			} else if (Status.OFFLINE == newStatus) {
				this.addOfflineUser(username);
			} else {
				this.addOnlineUser(username);
			}
		} else if (Status.BUSY == oldStatus) {
			iOfflineUser--;
			if (Status.ONLINE == newStatus) {
				this.addOnlineUser(username);
			} else if (Status.OFFLINE == newStatus) {
				this.addOfflineUser(username);
			} else {
				this.addBusyUser(username);
			}
		} else {
			if (Status.ONLINE == newStatus) {
				this.addOnlineUser(username);
			} else if (Status.BUSY == newStatus) {
				this.addBusyUser(username);
			} else {
				this.addOfflineUser(username);
			}
		}
	}

	private void moveSenderToUsers(String username, Status status) {
		this.userList.remove(username);
		if (Status.ONLINE == status) {
			iBusySender--;
			iOfflineSender--;
			iOnlineUser--;
			iBusyUser--;
			iOfflineUser--;
		} else if (Status.BUSY == status) {
			iOfflineSender--;
			iOnlineUser--;
			iBusyUser--;
			iOfflineUser--;
		} else {
			iOnlineUser--;
			iBusyUser--;
			iOfflineUser--;
		}
		this.addUserToUIList(username, status);
	}

	private void moveUserToSenders(String username, Status status) {
		this.userList.remove(username);
		if (Status.ONLINE == status) {
			iBusyUser--;
			iOfflineUser--;
		} else if (Status.BUSY == status) {
			iOfflineUser--;
		}
		this.addSenderToUIList(username, status);
	}

	private void addUserToUIList(String username, Status status) {
		if (Status.ONLINE == status) {
			this.addOnlineUser(username);
		} else if (Status.BUSY == status) {
			this.addBusyUser(username);
		} else {
			this.addOfflineUser(username);
		}
	}

	private void addOnlineUser(String username) {
		iBusyUser++;
		iOfflineUser++;
		this.userList.add(iOnlineUser, username);
	}

	private void addBusyUser(String username) {
		iOfflineUser++;
		this.userList.add(iBusyUser, username);
	}

	private void addOfflineUser(String username) {
		this.userList.add(iOfflineUser, username);
	}

	public String getUserAt(int position) {
		synchronized (this) {
			return this.userList.get(position);
		}
	}

	public ArrayList<String> getUserList() {
		synchronized (this) {
			return this.userList;
		}
	}

	/****/

	public Collection<String> getUsers() {
		synchronized (this) {
			Collection<String> users = new LinkedList<String>();
			for (User userInfo : this.users.values()) {
				users.add(userInfo.getUsername());
			}
			return users;
		}
	}

	public Collection<String> getOnlineUsers() {
		synchronized (this) {
			Collection<String> onlineUsers = new LinkedList<String>();
			for (User userInfo : this.users.values()) {
				if (userInfo.getStatus() == Status.OFFLINE || userInfo.getUsername().equals(broadcastWildcard))
					continue;
				onlineUsers.add(userInfo.getUsername());
			}
			return onlineUsers;
		}
	}

	public synchronized static void clearCommunity(){
		c = null;
	}
	
	public synchronized static Community obtainCommunity() {
		if (c == null)
			c = new Community();
		return c;
	}

}